package com.yueshang.neuron.core.aop;

import com.yueshang.common.entity.ResultResponse;
import com.yueshang.common.exception.BussinesException;
import com.yueshang.neuron.common.enums.ResultCodeEnum;
import com.yueshang.neuron.core.log.LogManager;
import com.yueshang.neuron.core.log.factory.LogTaskFactory;
import com.yueshang.neuron.core.shiro.ShiroKit;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.CredentialsException;
import org.apache.shiro.authc.DisabledAccountException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.yueshang.framework.support.HttpKit.getIp;
import static com.yueshang.framework.support.HttpKit.getRequest;


/**
 * <p>
 * 通用 Api Controller 全局异常处理
 * </p>
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);


    /**
     * 拦截业务异常
     */
    @ExceptionHandler(BussinesException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResultResponse notFount(BussinesException e) {
        LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));
        log.error("业务异常:", e);
        return ResultResponse.error(e.getCode(), e.getMessage());
    }

    /**
     * 用户未登录异常
     */
    @ExceptionHandler(AuthenticationException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public ResultResponse unAuth(AuthenticationException e) {
        log.error("用户未登陆：", e);
        return ResultResponse.error(ResultCodeEnum.UNAUTH_ERRO.getCode(), "未登录");
    }

    /**
     * 账号被冻结异常
     */
    @ExceptionHandler(DisabledAccountException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public ResultResponse accountLocked(DisabledAccountException e) {
        String username = getRequest().getParameter("accout");
        LogManager.me().executeLog(LogTaskFactory.loginLog(username, "账号被冻结", getIp()));
        return ResultResponse.error(ResultCodeEnum.DISABLE_ACCOUNT.getCode(), "账号被冻结");
    }

    /**
     * 账号密码错误异常
     */
    @ExceptionHandler(CredentialsException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public ResultResponse credentials(CredentialsException e) {
        String username = getRequest().getParameter("accout");
        LogManager.me().executeLog(LogTaskFactory.loginLog(username, "账号密码错误", getIp()));
        return ResultResponse.error(ResultCodeEnum.USER_PASSWORD_ERRO.getCode(), ResultCodeEnum.USER_PASSWORD_ERRO.getMsg());
    }

    /**
     * 无权访问该资源异常
     */
    @ExceptionHandler(UndeclaredThrowableException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public ResultResponse credentials(UndeclaredThrowableException e) {
        log.error("权限异常!", e);
        return ResultResponse.error(ResultCodeEnum.FORBB_ERRO.getCode(), "账号被冻结");
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResultResponse notFount(RuntimeException e) {
        LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));
        log.error("运行时异常:", e);
        return ResultResponse.error(ResultCodeEnum.EXCEPTION_FAIL.getCode(), ResultCodeEnum.EXCEPTION_FAIL.getMsg());
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public ResultResponse bindException(BindException e) {
//        LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));
        BindingResult bindingResult = e.getBindingResult();
        String errStr = "參數錯誤";
        if (null != bindingResult && bindingResult.hasErrors()) {
            List<Object> jsonList = new ArrayList<>();
            bindingResult.getFieldErrors().stream().forEach(fieldError -> {
                Map<String, Object> jsonObject = new HashMap<>(2);
                jsonObject.put("name", fieldError.getField());
                jsonObject.put("msg", fieldError.getDefaultMessage());
                jsonList.add(jsonObject);
            });
            errStr = jsonList.toString();
            log.error("运行时异常:", jsonList.toString());
        }
        return ResultResponse.error(ResultCodeEnum.PARM_ERRO.getCode(), errStr);

    }
}
